import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { UserService } from './user/user.service';
import { Reflector } from '@nestjs/core';
import { RedisService } from 'src/redis/redis.service';
import { Permission } from './user/entities/permission.entity';

@Injectable()
export class PermissionGuard implements CanActivate {
  @Inject(UserService)
  private userService: UserService;

  @Inject(Reflector)
  private reflector: Reflector;

  @Inject(RedisService)
  private redisService: RedisService;
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();

    // 从元数据获取所需权限
    const requirePermissions = this.reflector.getAllAndOverride<string[]>(
      'require-permissions',
      [context.getHandler(), context.getClass()],
    );

    // 如果路由不需要特定权限，则允许访问
    if (!requirePermissions || requirePermissions.length === 0) {
      return true;
    }

    const user = request.user;
    if (!user) {
      throw new UnauthorizedException('用户未登录');
    }

    // 从 Redis 获取权限
    let permissions = await this.redisService.listGet(
      `user_${user.id}_permissions`,
    );
    console.log('cache permissions');

    // 如果缓存中没有权限，从数据库获取
    if (!permissions || !permissions.length) {
      console.log('query permissions');
      const roleWithPermissions = await this.userService.findPermissionsByRoles(
        user.roles.map((role) => role.id),
      );

      permissions = roleWithPermissions
        .flatMap((role) => role.permissions)
        .map((permission) => permission.name);

      await this.redisService.listSet(
        `user_${user.id}_permissions`,
        permissions,
        60 * 30,
      );
    }

    // 检查用户是否拥有所有必需的权限
    const hasPermission = requirePermissions.every((requirePermission) =>
      permissions.some((permission) => permission === requirePermission),
    );

    console.log('权限', permissions, requirePermissions);

    if (hasPermission) {
      return true;
    } else {
      throw new UnauthorizedException('没有权限访问');
    }
  }
}
